package com.example.administrator.myapplication;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;

import com.slamtec.slamware.AbstractSlamwarePlatform;
import com.slamtec.slamware.action.MoveDirection;
import com.slamtec.slamware.discovery.DeviceManager;
import com.slamtec.slamware.geometry.PointF;
import com.slamtec.slamware.geometry.Size;
import com.slamtec.slamware.robot.LaserPoint;
import com.slamtec.slamware.robot.LaserScan;
import com.slamtec.slamware.robot.Map;
import com.slamtec.slamware.robot.MapType;
import com.slamtec.slamware.robot.Pose;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Vector;

import fr.arnaudguyon.smartgl.opengl.RenderObject;
import fr.arnaudguyon.smartgl.opengl.RenderPassSprite;
import fr.arnaudguyon.smartgl.opengl.SmartGLRenderer;
import fr.arnaudguyon.smartgl.opengl.SmartGLView;
import fr.arnaudguyon.smartgl.opengl.SmartGLViewController;
import fr.arnaudguyon.smartgl.opengl.Sprite;
import fr.arnaudguyon.smartgl.opengl.Texture;
import fr.arnaudguyon.smartgl.touch.TouchHelperEvent;
import io.github.controlwear.virtual.joystick.android.JoystickView;

import com.example.administrator.myapplication.BatteryView;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

public class MainActivity extends AppCompatActivity implements SmartGLViewController {

    private boolean isConnected = false;
    private AbstractSlamwarePlatform robotPlatform;
    private Map map = null;//地图


    private Pose robotPose = null;//机器人位置
    private int battery = 0;//电量（百分比）
    private int localizationQuality = 0;//定位准度,官方文档说明大于50认为是可信的。

    private RenderPassSprite renderPassSprite;
    private RenderPassSprite renderPositionSprite;
    private SmartGLView mSmartGLView;
    private Texture mSpriteTexture;
    private Texture mPointTexture;
    private Sprite mSprite;
    private Texture mMapTexture;
    private Sprite mMapSprite;
    private float mMapScale = 3f;

    private Vector<poseSprite> poseSprites = new Vector<poseSprite>();

    private float speed = 0;
    private float angle = 0;

    private int mMapPosX = 360;
    private int mMapPosY = 0;

    private long mPoseTime = SystemClock.uptimeMillis();
    private long mMapTime = SystemClock.uptimeMillis();

    private Button mConfirmBtn;
    private Button mSaveBtn;
    private Queue<GriphicsPose> pointQueue = new LinkedList<GriphicsPose>();

    private Spinner spinner;
    private ArrayAdapter<String> _Adapter;
    private ArrayList posItems = new ArrayList();
    HashMap<String, Pose> spinnerMap = new HashMap<String, Pose>();


    private Button mZoomInBtn;
    private Button mZoomOutBtn;
    private Button mMoveUp, mMoveDown, mMoveLeft, mMoveRight;
    private BatteryView batteryView;

    private EditText inputText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        inputText = (EditText) findViewById(R.id.nameText);
        batteryView = (BatteryView) findViewById(R.id.batteryView);

        mZoomInBtn = (Button) findViewById(R.id.ZoomIn);
        mZoomInBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapScale += 0.1f;
            }
        });

        mZoomOutBtn = (Button) findViewById(R.id.ZoomOut);
        mZoomOutBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapScale -= 0.1f;
            }
        });
        mMoveUp = (Button) findViewById(R.id.MoveUp);
        mMoveUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapPosY -= 10;
            }
        });
        mMoveDown = (Button) findViewById(R.id.MoveDown);
        mMoveDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapPosY += 10;
            }
        });
        mMoveLeft = (Button) findViewById(R.id.MoveLeft);
        mMoveLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapPosX -= 10;
            }
        });
        mMoveRight = (Button) findViewById(R.id.MoveRight);
        mMoveRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMapPosX += 10;
            }
        });

        spinner = (Spinner) findViewById(R.id.spinner);

        // 建立Adapter并且绑定数据源
        _Adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, posItems);
        //绑定 Adapter到控件
        spinner.setAdapter(_Adapter);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                                       int position, long id) {
                String str=parent.getItemAtPosition(position).toString();
                Toast.makeText(MainActivity.this, "你点击的是:"+str, Toast.LENGTH_SHORT).show();
                Log.e("onItemSelected", str);
                robotPlatform.moveTo(spinnerMap.get(str).getLocation());
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                // TODO Auto-generated method stub
            }
        });

        mSaveBtn = (Button) findViewById(R.id.saveBtn);
        mSaveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

//                spinner.notify();
                try {
                    JSONObject object = new JSONObject();
//                    JSONArray jsonarray = new JSONArray();//json数组，里面包含的内容为pet的所有对象
                    JSONObject jsonOrigin = new JSONObject();//pet对象，json形式
                    jsonOrigin.put("x", map.getOrigin().getX());
                    jsonOrigin.put("y", map.getOrigin().getY());
//                    jsonarray.put(jsonOrigin);//向json数组里面添加pet对象
                    object.put("origin", jsonOrigin);//向总对象里面添加包含pet的数组

                    JSONObject jsonDimesion = new JSONObject();//pet对象，json形式
                    jsonDimesion.put("width", map.getDimension().getWidth());
                    jsonDimesion.put("height", map.getDimension().getHeight());
                    object.put("dimesion", jsonDimesion);//向总对象里面添加包含pet的数组

                    JSONObject jsonResolution = new JSONObject();//pet对象，json形式
                    jsonResolution.put("x", map.getResolution().getX());
                    jsonResolution.put("y", map.getResolution().getY());
                    object.put("resolution", jsonResolution);//向总对象里面添加包含pet的数组

                    object.put("timestamp", map.getTimestamp());//向总对象里面添加包含pet的数组
                    byte[] data = map.getData();
                    JSONArray jsonArray = new JSONArray();
                    for(int i=0;i<data.length;i++) {
                        jsonArray.put(data[i]);
                    }
                    object.put("data", jsonArray);//向总对象里面添加包含pet的数组
//                    Log.e("JSONObject = ", object.toString());//生成返回字符串
                    try {

                        File folderPath = Environment.getExternalStorageDirectory();
                        File file = new File(folderPath, "description.json");
                        FileOutputStream fos = new FileOutputStream(file);
                        fos.write(object.toString().getBytes());
                        fos.close();
                    } catch (IOException e) {
                        Log.e("TAG", "Error in Writing: " + e.getLocalizedMessage());
                    }
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        mConfirmBtn = (Button) findViewById(R.id.button);
        mConfirmBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                GriphicsPose griphicsPose = new GriphicsPose(inputText.getText().toString(), robotPose);
                pointQueue.offer(griphicsPose);
                String key = inputText.getText().toString();//;"" + robotPose.getLocation().getX() + "," + robotPlatform.getLocation().getY();
                posItems.add(key);
                spinnerMap.put(key, robotPose);
                _Adapter.notifyDataSetChanged();

                try {
                // 3. build jsonObject
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.accumulate("name", inputText.getText().toString());
                    jsonObject.accumulate("x", robotPose.getLocation().getX());
                    jsonObject.accumulate("y", robotPlatform.getLocation().getY());
                    jsonObject.accumulate("yaw", robotPlatform.getPose().getYaw());
                    String json = jsonObject.toString();
                    new HttpAsyncTask().execute("http://192.168.11.246:5000/pose", json);
                } catch (Exception e) {
                    Log.d("InputStream", e.getLocalizedMessage());
                }

            }
        });
        mSmartGLView = (SmartGLView) findViewById(R.id.smartGLView);
        mSmartGLView.setDefaultRenderer(this);
        mSmartGLView.setController(this);

        JoystickView joystick = (JoystickView) findViewById(R.id.joystickView);
        joystick.setOnMoveListener(new JoystickView.OnMoveListener() {
            @Override
            public void onMove(int angle, int strength) {
                if (strength < 20) return;//相当于消除这个控件的抖动
                speed = strength;
                if (angle >= 45 && angle < 135) {
                    robotPlatform.moveBy(MoveDirection.FORWARD);
                } else if (angle >= 135 && angle < 225) {
                    robotPlatform.moveBy(MoveDirection.TURN_LEFT);
                } else if (angle >= 225 && angle < 315) {
                    robotPlatform.moveBy(MoveDirection.BACKWARD);
                } else {
                    robotPlatform.moveBy(MoveDirection.TURN_RIGHT);
//                    robotPlatform
                }
            }
        });

        robotPlatform = DeviceManager.connect("192.168.11.1", 1445);
    }
    public static String POST(String url, String value){
        InputStream inputStream = null;
        String result = "";
        try {

            // 1. create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // 2. make POST request to the given URL
            HttpPost httpPost = new HttpPost(url);

//            String json = "";
//
//
//            // 3. build jsonObject
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.accumulate("name", "android");
//            jsonObject.accumulate("x", 1.1111);
//            jsonObject.accumulate("y", 2.222);
//            jsonObject.accumulate("yaw", 3.33333);
//
//            // 4. convert JSONObject to JSON to String
//            json = jsonObject.toString();


            // ** Alternative way to convert Person object to JSON string usin Jackson Lib
            // ObjectMapper mapper = new ObjectMapper();
            // json = mapper.writeValueAsString(person);

            // 5. set json to StringEntity
            StringEntity se = new StringEntity(value);

            // 6. set httpPost Entity
            httpPost.setEntity(se);

            // 7. Set some headers to inform server about the type of the content
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-type", "application/json");

            // 8. Execute POST request to the given URL
            HttpResponse httpResponse = httpclient.execute(httpPost);

            // 9. receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();


            // 10. convert inputstream to string
//            if(inputStream != null)
//                result = convertInputStreamToString(inputStream);
//            else
//                result = "Did not work!";

        } catch (Exception e) {
            Log.d("InputStream", e.getLocalizedMessage());
        }

        // 11. return result
        return result;
    }
    private class HttpAsyncTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {

//            person = new Person();
//            person.setName(etName.getText().toString());
//            person.setCountry(etCountry.getText().toString());
//            person.setTwitter(etTwitter.getText().toString());

            return POST(urls[0],urls[1]);
        }
        // onPostExecute displays the results of the AsyncTask.
        @Override
        protected void onPostExecute(String result) {
            Toast.makeText(getBaseContext(), "Data Sent!", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onPrepareView(SmartGLView smartGLView) {
        Context context = smartGLView.getContext();

        SmartGLRenderer renderer = smartGLView.getSmartGLRenderer();
        renderPassSprite = new RenderPassSprite();
        renderPositionSprite = new RenderPassSprite();
        renderer.addRenderPass(renderPassSprite);  // add it only once for all Sprites
//        renderer.addRenderPass(renderPositionSprite);

        mSpriteTexture = new Texture(context, R.drawable.arrow);
        mPointTexture = new Texture(context, R.drawable.planet);

        mSprite = new Sprite(40, 40);	// 120 x 120 pixels
        mSprite.setPivot(0.5f, 0.5f);  // set position / rotation axis to the middle of the sprite
        mSprite.setTexture(mSpriteTexture);
        mSprite.setDisplayPriority(0);
        renderPassSprite.addSprite(mSprite);

//        RectF rectF = robotPlatform.getKnownArea(MapType.BITMAP_8BIT);
//        map = robotPlatform.getMap(MapType.BITMAP_8BIT, rectF);
//        Log.e("origin = ", map.getOrigin().toString());
//        Bitmap bitmap = Bitmap.createBitmap(
//                map.getDimension().getWidth(),
//                map.getDimension().getHeight(),
//                Bitmap.Config.ARGB_8888);
//        for (int poxY = 0; poxY < map.getDimension().getHeight(); poxY++) {
//            for (int posX = 0; posX < map.getDimension().getWidth(); posX++) {
//                bitmap.setPixel(posX, poxY, Color.argb(128+map.getData()[posX + (map.getDimension().getHeight() - poxY - 1) * map.getDimension().getWidth()], 255, 255, 255));
//            }
//        }

//        mMapTexture = new Texture(bitmap);
//        mMapSprite = new Sprite(map.getDimension().getWidth(), map.getDimension().getHeight());
        mMapSprite = new Sprite(0, 0);
        mMapSprite.setPos(mMapPosX, mMapPosY);
//        mMapSprite.
//        mMapSprite.setTexture(mMapTexture);
        mMapSprite.setScale(mMapScale, mMapScale);
        mMapSprite.setDisplayPriority(2);
        renderPassSprite.addSprite(mMapSprite);
//
//        Pose pose = robotPlatform.getPose();
//        float posX = (pose.getX()-map.getOrigin().getX())/map.getResolution().getX() + mMapPosX;
//        float posY = (mMapSprite.getScaleY() * mMapSprite.getHeight()) + mMapPosY - (pose.getY()-map.getOrigin().getY())/map.getResolution().getY();
//        mSprite.setPos(posX, posY);
//        mSprite.setRotation(calcRotation(pose.getYaw()));
    }

    @Override
    public void onReleaseView(SmartGLView smartGLView) {
        if (mSpriteTexture != null) {
            mSpriteTexture.release();
        }
    }

    @Override
    public void onResizeView(SmartGLView smartGLView) {

    }

    @Override
    public void onTick(SmartGLView smartGLView) {
        if (!pointQueue.isEmpty()) {//add point in the map.
            GriphicsPose griphicsPose = pointQueue.poll();
            if (griphicsPose != null) {
//                mPostionVec.add(pose);
//                Texture texture = new Texture(drawTextToBitmap(smartGLView.getContext(), R.drawable.planet, "" + (poseSprites.size() + 1)));
                Texture texture = new Texture(createBitmapFromText(griphicsPose.getName()));
//                Texture texture = new Texture(createBitmapFromLaserScan(robotPlatform.getLaserScan()));

                poseSprite mPoseSprite = new poseSprite(40, 40, griphicsPose.getPose());	// 120 x 120 pixels
                mPoseSprite.setPivot(0.5f, 0.5f);  // set position / rotation axis to the middle of the sprite
                mPoseSprite.setTexture(texture);
                mPoseSprite.setDisplayPriority(1);
//                float posX = (pose.getX()-map.getOrigin().getX())/map.getResolution().getX() * mMapScale + mMapPosX;
//                float posY = mMapSprite.getHeight() * mMapScale + mMapPosY - (pose.getY()-map.getOrigin().getY())/map.getResolution().getY() * mMapScale;
//                mPoseSprite.setPos(posX, posY);
                poseSprites.add(mPoseSprite);
                renderPassSprite.addSprite(mPoseSprite);
            }
        }


//        for(RenderObject sprite)

        if (SystemClock.uptimeMillis() - mMapTime > 200) {
            mMapTime = SystemClock.uptimeMillis();
            refreshSlamData();
            batteryView.setPower(battery);
        }
        if (map != null) {
            LaserScan laserScan = robotPlatform.getLaserScan();
            RectF rectF = robotPlatform.getKnownArea(MapType.BITMAP_8BIT);
            map = robotPlatform.getMap(MapType.BITMAP_8BIT, rectF);

            Bitmap bitmap = Bitmap.createBitmap(
                    map.getDimension().getWidth(),
                    map.getDimension().getHeight(),
                    Bitmap.Config.ARGB_8888);
            for (int poxY = 0; poxY < map.getDimension().getHeight(); poxY++) {
                for (int posX = 0; posX < map.getDimension().getWidth(); posX++) {
                    bitmap.setPixel(posX, poxY, Color.argb(128 + map.getData()[posX + (map.getDimension().getHeight() - poxY - 1) * map.getDimension().getWidth()], 255, 255, 255));
                }
            }
//            mMapTexture.release();
            mMapTexture = new Texture(bitmap);
            mMapSprite.resize(map.getDimension().getWidth(), map.getDimension().getHeight());
            mMapSprite.setPos(mMapPosX, mMapPosY);
            mMapSprite.setTexture(mMapTexture);
            mMapSprite.setScale(mMapScale, mMapScale);
        }

        if (map != null) {
            float posX = (robotPose.getX()-map.getOrigin().getX())/map.getResolution().getX() * mMapScale + mMapPosX;
            float posY = mMapSprite.getHeight() * mMapScale + mMapPosY - (robotPose.getY()-map.getOrigin().getY())/map.getResolution().getY() * mMapScale;
            mSprite.setPos(posX, posY);
            float rotate = calcRotation(robotPose.getYaw());
            mSprite.setRotation(rotate);
        }
//        Vector<RenderObject> posSprite = renderPositionSprite.getRenderObjects();
        for(Iterator it = poseSprites.iterator(); it.hasNext();){
            poseSprite its = (poseSprite)it.next();
            float posX = (its.getPose().getX()-map.getOrigin().getX())/map.getResolution().getX() * mMapScale + mMapPosX;
            float posY = mMapSprite.getHeight() * mMapScale + mMapPosY - (its.getPose().getY()-map.getOrigin().getY())/map.getResolution().getY() * mMapScale;
            its.setPos(posX, posY);
            its.setDisplayPriority(1);
//            its.setPos();
        }

    }

    @Override
    public void onTouchEvent(SmartGLView smartGLView, TouchHelperEvent event) {
    }

    @Override
    protected void onPause() {
        if (mSmartGLView != null) {
            mSmartGLView.onPause();
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mSmartGLView != null) {
            mSmartGLView.onResume();
        }
    }

    float calcRotation(float yaw) {
        float rotate = (float)Math.toDegrees(yaw);
        if (rotate < 0)
            rotate = 360.0f - rotate;
        if (rotate > 0 && rotate < 180)
            rotate = (360.0f - (rotate % 360f));
        return rotate;
//        Log.e("calcRotation = ", "" + rotate);
//        return (360.0f - (rotate % 360f));
    }
    boolean refreshSlamData() {
        boolean ret = false;
        try {
            RectF rectF = robotPlatform.getKnownArea(MapType.BITMAP_8BIT);
            map = robotPlatform.getMap(MapType.BITMAP_8BIT, rectF);
            robotPose = robotPlatform.getPose();
            battery = robotPlatform.getBatteryPercentage();
            localizationQuality = robotPlatform.getLocalizationQuality();
            ret = true;
        } catch (Exception e) {
            Log.v("robotPlatform", "false");
            e.printStackTrace();
            isConnected = false;
            Toast.makeText(MainActivity.this, "" + e.getMessage(), Toast.LENGTH_LONG).show();
        }

        return ret;
    }
    public Bitmap drawTextToBitmap(Context gContext,
                                   int gResId,
                                   String gText) {
        Resources resources = gContext.getResources();
        float scale = resources.getDisplayMetrics().density;
        Bitmap bitmap =
                BitmapFactory.decodeResource(resources, gResId);

        android.graphics.Bitmap.Config bitmapConfig =
                bitmap.getConfig();
        // set default bitmap config if none
        if(bitmapConfig == null) {
            bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
        }
        // resource bitmaps are imutable,
        // so we need to convert it to mutable one
        bitmap = bitmap.copy(bitmapConfig, true);

        Canvas canvas = new Canvas(bitmap);
        // new antialised Paint
        Paint paint = new Paint(Paint.FAKE_BOLD_TEXT_FLAG);
        // text color - #3D3D3D
        paint.setColor(Color.rgb(255, 0, 0));
        // text size in pixels
        paint.setTextSize((int) (150 * scale));
        // text shadow
        paint.setShadowLayer(1f, 0f, 1f, Color.MAGENTA);

        // draw text to the Canvas center
        Rect bounds = new Rect();
        paint.getTextBounds(gText, 0, gText.length(), bounds);
        int x = (bitmap.getWidth() - bounds.width())/2;
        int y = (bitmap.getHeight() + bounds.height())/2;

        canvas.drawText(gText, x, y, paint);

        return bitmap;
    }
    private Bitmap createBitmapFromText(String text) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(20);
        paint.setColor(0xFF112233);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        int width = bounds.right - bounds.left;
        int height = bounds.bottom - bounds.top;
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        if (bitmap != null) {
            Canvas canvas = new Canvas(bitmap);
//            canvas.drawColor(0xFFdd8833);
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            canvas.drawText(text, -bounds.left, -bounds.top, paint);
        }
        return bitmap;
    }
}
